home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Games Extra 1996 September
/
Amiga Games Extra CD-ROM 9-1996.iso
/
userbox
/
publicdomain
/
vim-4.2
/
src
/
cmdcmds.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-06-17
|
28KB
|
1,236 lines
/* vi:set ts=4 sw=4:
*
* VIM - Vi IMproved by Bram Moolenaar
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
*/
/*
* cmdcmds.c: functions for command line commands
*/
#include "vim.h"
#include "globals.h"
#include "proto.h"
#include "option.h"
#ifdef USE_TMPNAM
# define mktemp(a) tmpnam(a)
#endif
extern char *mktemp __ARGS((char *));
#ifdef OS2
static void check_tmpenv __ARGS((void));
#endif
#ifdef VIMINFO
static char_u *viminfo_filename __ARGS((char_u *));
static void do_viminfo __ARGS((FILE *fp_in, FILE *fp_out, int want_info, int want_marks, int force_read));
static int read_viminfo_up_to_marks __ARGS((char_u *line, FILE *fp, int force));
#endif /* VIMINFO */
void
do_ascii()
{
int c;
char buf1[20];
char buf2[20];
char_u buf3[3];
c = gchar_cursor();
if (c == NL) /* NUL is stored as NL */
c = NUL;
if (isprintchar(c) && (c < ' ' || c > '~'))
{
transchar_nonprint(buf3, c);
sprintf(buf1, " <%s>", (char *)buf3);
}
else
buf1[0] = NUL;
if (c >= 0x80)
sprintf(buf2, " <M-%s>", transchar(c & 0x7f));
else
buf2[0] = NUL;
sprintf((char *)IObuff, "<%s>%s%s %d, Hex %02x, Octal %03o",
transchar(c), buf1, buf2, c, c, c);
msg(IObuff);
}
/*
* align text:
* type = -1 left aligned
* type = 0 centered
* type = 1 right aligned
*/
void
do_align(start, end, width, type)
linenr_t start;
linenr_t end;
int width;
int type;
{
FPOS pos;
int len;
int indent = 0;
int new_indent = 0; /* init for GCC */
char_u *first;
char_u *last;
int save;
#ifdef RIGHTLEFT
if (curwin->w_p_rl)
type = -type; /* switch left and right aligning */
#endif
pos = curwin->w_cursor;
if (type == -1) /* left align: width is used for new indent */
{
if (width >= 0)
indent = width;
}
else
{
/*
* if 'textwidth' set, use it
* else if 'wrapmargin' set, use it
* if invalid value, use 80
*/
if (width <= 0)
width = curbuf->b_p_tw;
if (width == 0 && curbuf->b_p_wm > 0)
width = Columns - curbuf->b_p_wm;
if (width <= 0)
width = 80;
}
if (u_save((linenr_t)(start - 1), (linenr_t)(end + 1)) == FAIL)
return;
for (curwin->w_cursor.lnum = start;
curwin->w_cursor.lnum <= end; ++curwin->w_cursor.lnum)
{
/* find the first non-blank character */
first = skipwhite(ml_get_curline());
/* find the character after the last non-blank character */
for (last = first + STRLEN(first);
last > first && vim_iswhite(last[-1]); --last)
;
save = *last;
*last = NUL;
len = linetabsize(first); /* get line length */
*last = save;
if (len == 0) /* skip blank lines */
continue;
switch (type)
{
case -1: new_indent = indent; /* left align */
break;
case 0: new_indent = (width - len) / 2; /* center */
break;
case 1: new_indent = width - len; /* right align */
break;
}
if (new_indent < 0)
new_indent = 0;
set_indent(new_indent, TRUE); /* set indent */
}
curwin->w_cursor = pos;
beginline(TRUE);
updateScreen(NOT_VALID);
}
void
do_retab(start, end, new_ts, force)
linenr_t start;
linenr_t end;
int new_ts;
int force;
{
linenr_t lnum;
int got_tab = FALSE;
long num_spaces = 0;
long num_tabs;
long len;
long col;
long vcol;
long start_col = 0; /* For start of white-space string */
long start_vcol = 0; /* For start of white-space string */
int temp;
long old_len;
char_u *ptr;
char_u *new_line = (char_u *)1; /* init to non-NULL */
int did_something = FALSE;
int did_undo; /* called u_save for current line */
if (new_ts == 0)
new_ts = curbuf->b_p_ts;
for (lnum = start; !got_int && lnum <= end; ++lnum)
{
ptr = ml_get(lnum);
col = 0;
vcol = 0;
did_undo = FALSE;
for (;;)
{
if (vim_iswhite(ptr[col]))
{
if (!got_tab && num_spaces == 0)
{
/* First consecutive white-space */
start_vcol = vcol;
start_col = col;
}
if (ptr[col] == ' ')
num_spaces++;
else
got_tab = TRUE;
}
else
{
if (got_tab || (force && num_spaces > 1))
{
/* Retabulate this string of white-space */
/* len is virtual length of white string */
len = num_spaces = vcol - start_vcol;
num_tabs = 0;
if (!curbuf->b_p_et)
{
temp = new_ts - (start_vcol % new_ts);
if (num_spaces >= temp)
{
num_spaces -= temp;
num_tabs++;
}
num_tabs += num_spaces / new_ts;
num_spaces -= (num_spaces / new_ts) * new_ts;
}
if (curbuf->b_p_et || got_tab ||
(num_spaces + num_tabs < len))
{
if (did_undo == FALSE)
{
did_undo = TRUE;
if (u_save((linenr_t)(lnum - 1),
(linenr_t)(lnum + 1)) == FAIL)
{
new_line = NULL; /* flag out-of-memory */
break;
}
}
/* len is actual number of white characters used */
len = num_spaces + num_tabs;
old_len = STRLEN(ptr);
new_line = lalloc(old_len - col + start_col + len + 1,
TRUE);
if (new_line == NULL)
break;
if (start_col > 0)
vim_memmove(new_line, ptr, (size_t)start_col);
vim_memmove(new_line + start_col + len,
ptr + col, (size_t)(old_len - col + 1));
ptr = new_line + start_col;
for (col = 0; col < len; col++)
ptr[col] = (col < num_tabs) ? '\t' : ' ';
ml_replace(lnum, new_line, FALSE);
did_something = TRUE;
ptr = new_line;
col = start_col + len;
}
}
got_tab = FALSE;
num_spaces = 0;
}
if (ptr[col] == NUL)
break;
vcol += chartabsize(ptr[col++], (colnr_t)vcol);
}
if (new_line == NULL) /* out of memory */
break;
line_breakcheck();
}
if (got_int)
emsg(e_interr);
if (did_something)
CHANGED;
curbuf->b_p_ts = new_ts;
coladvance(curwin->w_curswant);
}
/*
* :move command - move lines line1-line2 to line n
*
* return FAIL for failure, OK otherwise
*/
int
do_move(line1, line2, n)
linenr_t line1;
linenr_t line2;
linenr_t n;
{
char_u *str;
linenr_t l;
linenr_t extra; /* Num lines added before line1 */
linenr_t num_lines; /* Num lines moved */
linenr_t last_line; /* Last line in file after adding new text */
int has_mark;
if (n >= line1 && n < line2)
{
EMSG("Move lines into themselves");
return FAIL;
}
num_lines = line2 - line1 + 1;
/*
* First we copy the old text to its new location -- webb
*/
if (u_save(n, n + 1) == FAIL)
return FAIL;
for (extra = 0, l = line1; l <= line2; l++)
{
str = strsave(ml_get(l + extra));
if (str != NULL)
{
has_mark = ml_has_mark(l + extra);
ml_append(n + l - line1, str, (colnr_t)0, FALSE);
vim_free(str);
if (has_mark)
ml_setmarked(n + l - line1 + 1);
if (n < line1)
extra++;
}
}
/*
* Now we must be careful adjusting our marks so that we don't overlap our
* mark_adjust() calls.
*
* We adjust the marks within the old text so that they refer to the
* last lines of the file (temporarily), because we know no other marks
* will be set there since these line numbers did not exist until we added
* our new lines.
*
* Then we adjust the marks on lines between the old and new text positions
* (either forwards or backwards).
*
* And Finally we adjust the marks we put at the end of the file back to
* their final destination at the new text position -- webb
*/
last_line = curbuf->b_ml.ml_line_count;
mark_adjust(line1, line2, last_line - line2, 0L);
if (n >= line2)
mark_adjust(line2 + 1, n, -num_lines, 0L);
else
mark_adjust(n + 1, line1 - 1, num_lines, 0L);
mark_adjust(last_line - num_lines + 1, last_line,
-(last_line - n - extra), 0L);
/*
* Now we delete the original text -- webb
*/
if (u_save(line1 + extra - 1, line2 + extra + 1) == FAIL)
return FAIL;
for (l = line1; l <= line2; l++)
ml_delete(line1 + extra, TRUE);
CHANGED;
if (!global_busy && num_lines > p_report)
smsg((char_u *)"%ld line%s moved", num_lines, plural(num_lines));
return OK;
}
/*
* :copy command - copy lines line1-line2 to line n
*/
void
do_copy(line1, line2, n)
linenr_t line1;
linenr_t line2;
linenr_t n;
{
linenr_t lnum;
char_u *p;
mark_adjust(n + 1, MAXLNUM, line2 - line1 + 1, 0L);
/*
* there are three situations:
* 1. destination is above line1
* 2. destination is between line1 and line2
* 3. destination is below line2
*
* n = destination (when starting)
* curwin->w_cursor.lnum = destination (while copying)
* line1 = start of source (while copying)
* line2 = end of source (while copying)
*/
if (u_save(n, n + 1) == FAIL)
return;
curwin->w_cursor.lnum = n;
lnum = line2 - line1 + 1;
while (line1 <= line2)
{
/* need to use strsave() because the line will be unlocked
within ml_append */
p = strsave(ml_get(line1));
if (p != NULL)
{
ml_append(curwin->w_cursor.lnum, p, (colnr_t)0, FALSE);
vim_free(p);
}
/* situation 2: skip already copied lines */
if (line1 == n)
line1 = curwin->w_cursor.lnum;
++line1;
if (curwin->w_cursor.lnum < line1)
++line1;
if (curwin->w_cursor.lnum < line2)
++line2;
++curwin->w_cursor.lnum;
}
CHANGED;
msgmore((long)lnum);
}
/*
* Handle the ":!cmd" command. Also for ":r !cmd" and ":w !cmd"
* Bangs in the argument are replaced with the previously entered command.
* Remember the argument.
*/
void
do_bang(addr_count, line1, line2, forceit, arg, do_in, do_out)
int addr_count;
linenr_t line1, line2;
int forceit;
char_u *arg;
int do_in, do_out;
{
static char_u *prevcmd = NULL; /* the previous command */
char_u *newcmd = NULL; /* the new command */
int ins_prevcmd;
char_u *t;
char_u *p;
char_u *trailarg;
int len;
int scroll_save = msg_scroll;
/*
* Disallow shell commands from .exrc and .vimrc in current directory for
* security reasons.
*/
if (secure)
{
secure = 2;
emsg(e_curdir);
return;
}
if (addr_count == 0) /* :! */
{
msg_scroll = FALSE; /* don't scroll here */
autowrite_all();
msg_scroll = scroll_save;
}
/*
* Try to find an embedded bang, like in :!<cmd> ! [args]
* (:!! is indicated by the 'forceit' variable)
*/
ins_prevcmd = forceit;
trailarg = arg;
do
{
len = STRLEN(trailarg) + 1;
if (newcmd != NULL)
len += STRLEN(newcmd);
if (ins_prevcmd)
{
if (prevcmd == NULL)
{
emsg(e_noprev);
vim_free(newcmd);
return;
}
len += STRLEN(prevcmd);
}
if ((t = alloc(len)) == NULL)
{
vim_free(newcmd);
return;
}
*t = NUL;
if (newcmd != NULL)
STRCAT(t, newcmd);
if (ins_prevcmd)
STRCAT(t, prevcmd);
p = t + STRLEN(t);
STRCAT(t, trailarg);
vim_free(newcmd);
newcmd = t;
/*
* Scan the rest of the argument for '!', which is replaced by the
* previous command. "\!" is replaced by "!" (this is vi compatible).
*/
trailarg = NULL;
while (*p)
{
if (*p == '!')
{
if (p > newcmd && p[-1] == '\\')
vim_memmove(p - 1, p, (size_t)(STRLEN(p) + 1));
else
{
trailarg = p;
*trailarg++ = NUL;
ins_prevcmd = TRUE;
break;
}
}
++p;
}
} while (trailarg != NULL);
vim_free(prevcmd);
prevcmd = newcmd;
if (bangredo) /* put cmd in redo buffer for ! command */
{
AppendToRedobuff(prevcmd);
AppendToRedobuff((char_u *)"\n");
bangredo = FALSE;
}
if (addr_count == 0) /* :! */
{
/* echo the command */
msg_start();
msg_outchar(':');
msg_outchar('!');
msg_outtrans(prevcmd);
msg_clr_eos();
windgoto(msg_row, msg_col);
do_shell(prevcmd);
}
else /* :range! */
do_filter(line1, line2, prevcmd, do_in, do_out);
}
/*
* call a shell to execute a command
*/
void
do_shell(cmd)
char_u *cmd;
{
BUF *buf;
int save_nwr;
/*
* Disallow shell commands from .exrc and .vimrc in current directory for
* security reasons.
*/
if (secure)
{
secure = 2;
emsg(e_curdir);
msg_end();
return;
}
#ifdef WIN32
/*
* Check if external commands are allowed now.
*/
if (can_end_termcap_mode(TRUE) == FALSE)
return;
#endif
/*
* For autocommands we want to get the output on the current screen, to
* avoid having to type return below.
*/
msg_outchar('\r'); /* put cursor at start of line */
#ifdef AUTOCMD
if (!autocmd_busy)
#endif
stoptermcap();
msg_outchar('\n'); /* may shift screen one line up */
/* warning message before calling the shell */
if (p_warn
#ifdef AUTOCMD
&& !autocmd_busy
#endif
)
for (buf = firstbuf; buf; buf = buf->b_next)
if (buf->b_changed)
{
MSG_OUTSTR("[No write since last change]\n");
break;
}
/* This windgoto is required for when the '\n' resulted in a "delete line 1"
* command to the terminal. */
windgoto(msg_row, msg_col);
cursor_on();
(void)call_shell(cmd, SHELL_COOKED);
need_check_timestamps = TRUE;
/*
* put the message cursor at the end of the screen, avoids wait_return() to
* overwrite the text that the external command showed
*/
msg_pos((int)Rows - 1, 0);
#ifdef AUTOCMD
if (!autocmd_busy)
#endif
{
/*
* If K_TI is defined, we assume that we switch screens when
* starttermcap() is called. In that case we really want to wait for
* "hit return to continue".
*/
save_nwr = no_wait_return;
if (*T_TI != NUL)
no_wait_return = FALSE;
#ifdef AMIGA
wait_return(term_console ? -1 : TRUE); /* see below */
#else
wait_return(TRUE);
#endif
no_wait_return = save_nwr;
starttermcap(); /* start termcap if not done by wait_return() */
/*
* In an Amiga window redrawing is caused by asking the window size.
* If we got an interrupt this will not work. The chance that the
* window size is wrong is very small, but we need to redraw the
* screen. Don't do this if ':' hit in wait_return(). THIS IS UGLY
* but it saves an extra redraw.
*/
#ifdef AMIGA
if (skip_redraw) /* ':' hit in wait_return() */
must_redraw = CLEAR;
else if (term_console)
{
OUTSTR("\033[0 q"); /* get window size */
if (got_int)
must_redraw = CLEAR; /* if got_int is TRUE, redraw needed */
else
must_redraw = 0; /* no extra redraw needed */
}
#endif /* AMIGA */
}
#ifdef AUTOCMD
else
must_redraw = CLEAR;
#endif
}
/*
* do_filter: filter lines through a command given by the user
*
* We use temp files and the call_shell() routine here. This would normally
* be done using pipes on a UNIX machine, but this is more portable to
* non-unix machines. The call_shell() routine needs to be able
* to deal with redirection somehow, and should handle things like looking
* at the PATH env. variable, and adding reasonable extensions to the
* command name given by the user. All reasonable versions of call_shell()
* do this.
* We use input redirection if do_in is TRUE.
* We use output redirection if do_out is TRUE.
*/
void
do_filter(line1, line2, buff, do_in, do_out)
linenr_t line1, line2;
char_u *buff;
int do_in, do_out;
{
#ifdef USE_TMPNAM
char_u itmp[L_tmpnam]; /* use tmpnam() */
char_u otmp[L_tmpnam];
#else
char_u itmp[TMPNAMELEN];
char_u otmp[TMPNAMELEN];
#endif
linenr_t linecount;
FPOS cursor_save;
/*
* Disallow shell commands from .exrc and .vimrc in current directory for
* security reasons.
*/
if (secure)
{
secure = 2;
emsg(e_curdir);
return;
}
if (*buff == NUL) /* no filter command */
return;
#ifdef WIN32
/*
* Check if external commands are allowed now.
*/
if (can_end_termcap_mode(TRUE) == FALSE)
return;
#endif
cursor_save = curwin->w_cursor;
linecount = line2 - line1 + 1;
curwin->w_cursor.lnum = line1;
curwin->w_cursor.col = 0;
/*
* 1. Form temp file names
* 2. Write the lines to a temp file
* 3. Run the filter command on the temp file
* 4. Read the output of the command into the buffer
* 5. Delete the original lines to be filtered
* 6. Remove the temp files
*/
#ifndef USE_TMPNAM /* tmpnam() will make its own name */
# ifdef OS2
check_tmpenv();
expand_env(TMPNAME1, itmp, TMPNAMELEN);
expand_env(TMPNAME2, otmp, TMPNAMELEN);
# else
STRCPY(itmp, TMPNAME1);
STRCPY(otmp, TMPNAME2);
# endif
#endif
if ((do_in && *mktemp((char *)itmp) == NUL) ||
(do_out && *mktemp((char *)otmp) == NUL))
{
emsg(e_notmp);
return;
}
/*
* The writing and reading of temp files will not be shown.
* Vi also doesn't do this and the messages are not very informative.
*/
++no_wait_return; /* don't call wait_return() while busy */
if (do_in && buf_write(curbuf, itmp, NULL, line1, line2,
FALSE, 0, FALSE, TRUE) == FAIL)
{
msg_outchar('\n'); /* keep message from buf_write() */
--no_wait_return;
(void)emsg2(e_notcreate, itmp); /* will call wait_return */
goto filterend;
}
if (!do_out)
msg_outchar('\n');
#if (defined(UNIX) && !defined(ARCHIE)) || defined(OS2)
/*
* put braces around the command (for concatenated commands)
*/
sprintf((char *)IObuff, "(%s)", (char *)buff);
if (do_in)
{
STRCAT(IObuff, " < ");
STRCAT(IObuff, itmp);
}
#else
/*
* for shells that don't understand braces around commands, at least allow
* the use of commands in a pipe.
*/
STRCPY(IObuff, buff);
if (do_in)
{
char_u *p;
/*
* If there is a pipe, we have to put the '<' in front of it
*/
p = vim_strchr(IObuff, '|');
if (p)
*p = NUL;
STRCAT(IObuff, " < ");
STRCAT(IObuff, itmp);
p = vim_strchr(buff, '|');
if (p)
STRCAT(IObuff, p);
}
#endif
if (do_out)
{
char_u *p;
if ((p = vim_strchr(p_srr, '%')) != NULL && p[1] == 's')
{
p = IObuff + STRLEN(IObuff);
*p++ = ' '; /* not really needed? Not with sh, ksh or bash */
sprintf((char *)p, (char *)p_srr, (char *)otmp);
}
else
sprintf((char *)IObuff + STRLEN(IObuff), " %s %s",
(char *)p_srr, (char *)otmp);
}
windgoto((int)Rows - 1, 0);
cursor_on();
/*
* When not redirecting the output the command can write anything to the
* screen. If 'shellredir' is equal to ">", screen may be messed up by
* stderr output of external command. Clear the screen later.
* If do_in is FALSE, this could be something like ":r !cat", which may
* also mess up the screen, clear it later.
*/
if (!do_out || STRCMP(p_srr, ">") == 0 || !do_in)
must_redraw = CLEAR;
else
redraw_later(NOT_VALID);
/*
* When call_shell() fails wait_return() is called to give the user a
* chance to read the error messages. Otherwise errors are ignored, so you
* can see the error messages from the command that appear on stdout; use
* 'u' to fix the text
* Switch to cooked mode when not redirecting stdin, avoids that something
* like ":r !cat" hangs.
*/
if (call_shell(IObuff, SHELL_FILTER | SHELL_COOKED) == FAIL)
{
must_redraw = CLEAR;
wait_return(FALSE);
}
need_check_timestamps = TRUE;
if (do_out)
{
if (u_save((linenr_t)(line2), (linenr_t)(line2 + 1)) == FAIL)
{
goto error;
}
if (readfile(otmp, NULL, line2, FALSE, (linenr_t)0, MAXLNUM, TRUE)
== FAIL)
{
msg_outchar('\n');
emsg2(e_notread, otmp);
goto error;
}
if (do_in)
{
/* put cursor on first filtered line for ":range!cmd" */
curwin->w_cursor.lnum = line1;
dellines(linecount, TRUE, TRUE);
curbuf->b_op_start.lnum -= linecount; /* adjust '[ */
curbuf->b_op_end.lnum -= linecount; /* adjust '] */
}
else
{
/* put cursor on last new line for ":r !cmd" */
curwin->w_cursor.lnum = curbuf->b_op_end.lnum;
linecount = curbuf->b_op_end.lnum - curbuf->b_op_start.lnum + 1;
}
beginline(TRUE); /* cursor on first non-blank */
--no_wait_return;
if (linecount > p_report)
{
if (do_in)
{
sprintf((char *)msg_buf, "%ld lines filtered", (long)linecount);
if (msg(msg_buf) && !msg_scroll)
keep_msg = msg_buf; /* display message after redraw */
}
else
msgmore((long)linecount);
}
}
else
{
error:
/* put cursor back in same position for ":w !cmd" */
curwin->w_cursor = cursor_save;
--no_wait_return;
wait_return(FALSE);
}
filterend:
vim_remove(itmp);
vim_remove(otmp);
}
#ifdef OS2
/*
* If $TMP is not defined, construct a sensible default.
* This is required for TMPNAME1 and TMPNAME2 to work.
*/
static void
check_tmpenv()
{
char_u *envent;
if (getenv("TMP") == NULL)
{
envent = alloc(8);
if (envent != NULL)
{
strcpy(envent, "TMP=C:/");
putenv(envent);
}
}
}
#endif /* OS2 */
#ifdef VIMINFO
static int no_viminfo __ARGS((void));
static int
no_viminfo()
{
/* "vim -i NONE" does not read or write a viminfo file */
return (use_viminfo != NULL && STRCMP(use_viminfo, "NONE") == 0);
}
/*
* read_viminfo() -- Read the viminfo file. Registers etc. which are already
* set are not over-written unless force is TRUE. -- webb
*/
int
read_viminfo(file, want_info, want_marks, force)
char_u *file;
int want_info;
int want_marks;
int force;
{
FILE *fp;
if (no_viminfo())
return FAIL;
file = viminfo_filename(file); /* may set to default if NULL */
if ((fp = fopen((char *)file, READBIN)) == NULL)
return FAIL;
do_viminfo(fp, NULL, want_info, want_marks, force);
fclose(fp);
return OK;
}
/*
* write_viminfo() -- Write the viminfo file. The old one is read in first so
* that effectively a merge of current info and old info is done. This allows
* multiple vims to run simultaneously, without losing any marks etc. If
* force is TRUE, then the old file is not read in, and only internal info is
* written to the file. -- webb
*/
void
write_viminfo(file, force)
char_u *file;
int force;
{
FILE *fp_in = NULL;
FILE *fp_out = NULL;
#ifdef USE_TMPNAM
char_u tmpname[L_tmpnam]; /* use tmpnam() */
#else
char_u tmpname[TMPNAMELEN];
#endif
if (no_viminfo())
return;
#ifndef USE_TMPNAM /* tmpnam() will make its own name */
# ifdef OS2
check_tmpenv();
expand_env(TMPNAME2, tmpname, TMPNAMELEN);
# else
STRCPY(tmpname, TMPNAME2);
# endif
#endif
file = viminfo_filename(file); /* may set to default if NULL */
file = strsave(file); /* make a copy, don't want NameBuff */
if (file != NULL)
{
fp_in = fopen((char *)file, READBIN);
if (fp_in == NULL)
fp_out = fopen((char *)file, WRITEBIN);
else if (*mktemp((char *)tmpname) != NUL)
fp_out = fopen((char *)tmpname, WRITEBIN);
}
if (file == NULL || fp_out == NULL)
{
EMSG2("Can't write viminfo file %s!", file == NULL ? (char_u *)"" :
fp_in == NULL ? file : tmpname);
if (fp_in != NULL)
fclose(fp_in);
vim_free(file);
return;
}
do_viminfo(fp_in, fp_out, !force, !force, FALSE);
fclose(fp_out); /* errors are ignored !? */
if (fp_in != NULL)
{
fclose(fp_in);
if (vim_rename(tmpname, file) == -1)
vim_remove(tmpname);
}
vim_free(file);
}
static char_u *
viminfo_filename(file)
char_u *file;
{
if (file == NULL || *file == NUL)
{
expand_env(use_viminfo == NULL ? (char_u *)VIMINFO_FILE : use_viminfo,
NameBuff, MAXPATHL);
return NameBuff;
}
return file;
}
/*
* do_viminfo() -- Should only be called from read_viminfo() & write_viminfo().
*/
static void
do_viminfo(fp_in, fp_out, want_info, want_marks, force_read)
FILE *fp_in;
FILE *fp_out;
int want_info;
int want_marks;
int force_read;
{
int count = 0;
int eof = FALSE;
char_u *line;
if ((line = alloc(LSIZE)) == NULL)
return;
if (fp_in != NULL)
{
if (want_info)
eof = read_viminfo_up_to_marks(line, fp_in, force_read);
else
/* Skip info, find start of marks */
while (!(eof = vim_fgets(line, LSIZE, fp_in)) && line[0] != '>')
;
}
if (fp_out != NULL)
{
/* Write the info: */
fprintf(fp_out, "# This viminfo file was generated by vim\n");
fprintf(fp_out, "# You may edit it if you're careful!\n\n");
write_viminfo_search_pattern(fp_out);
write_viminfo_sub_string(fp_out);
write_viminfo_history(fp_out);
write_viminfo_registers(fp_out);
write_viminfo_filemarks(fp_out);
count = write_viminfo_marks(fp_out);
}
if (fp_in != NULL && want_marks)
copy_viminfo_marks(line, fp_in, fp_out, count, eof);
vim_free(line);
}
/*
* read_viminfo_up_to_marks() -- Only called from do_viminfo(). Reads in the
* first part of the viminfo file which contains everything but the marks that
* are local to a file. Returns TRUE when end-of-file is reached. -- webb
*/
static int
read_viminfo_up_to_marks(line, fp, force)
char_u *line;
FILE *fp;
int force;
{
int eof;
prepare_viminfo_history(force ? 9999 : 0);
eof = vim_fgets(line, LSIZE, fp);
while (!eof && line[0] != '>')
{
switch (line[0])
{
case NUL:
case '\r':
case '\n':
case '#': /* A comment */
eof = vim_fgets(line, LSIZE, fp);
break;
case '"':
eof = read_viminfo_register(line, fp, force);
break;
case '/': /* Search string */
case '&': /* Substitute search string */
case '~': /* Last search string, followed by '/' or '&' */
eof = read_viminfo_search_pattern(line, fp, force);
break;
case '$':
eof = read_viminfo_sub_string(line, fp, force);
break;
case ':':
case '?':
eof = read_viminfo_history(line, fp);
break;
case '\'':
/* How do we have a file mark when the file is not in the
* buffer list?
*/
eof = read_viminfo_filemark(line, fp, force);
break;
#if 0
case '+':
/* eg: "+40 /path/dir file", for running vim with no args */
eof = vim_fgets(line, LSIZE, fp);
break;
#endif
default:
EMSG2("viminfo: Illegal starting char in line %s", line);
eof = vim_fgets(line, LSIZE, fp);
break;
}
}
finish_viminfo_history();
return eof;
}
/*
* check string read from viminfo file
* remove '\n' at the end of the line
* - replace CTRL-V CTRL-V with CTRL-V
* - replace CTRL-V 'n' with '\n'
*/
void
viminfo_readstring(p)
char_u *p;
{
while (*p != NUL && *p != '\n')
{
if (*p == Ctrl('V'))
{
if (p[1] == 'n')
p[0] = '\n';
vim_memmove(p + 1, p + 2, STRLEN(p));
}
++p;
}
*p = NUL;
}
/*
* write string to viminfo file
* - replace CTRL-V with CTRL-V CTRL-V
* - replace '\n' with CTRL-V 'n'
* - add a '\n' at the end
*/
void
viminfo_writestring(fd, p)
FILE *fd;
char_u *p;
{
register int c;
while ((c = *p++) != NUL)
{
if (c == Ctrl('V') || c == '\n')
{
putc(Ctrl('V'), fd);
if (c == '\n')
c = 'n';
}
putc(c, fd);
}
putc('\n', fd);
}
#endif /* VIMINFO */
/*
* Implementation of ":fixdel", also used by get_stty().
* <BS> resulting <Del>
* ^? ^H
* not ^? ^?
*/
void
do_fixdel()
{
char_u *p;
p = find_termcode((char_u *)"kb");
add_termcode((char_u *)"kD", p != NULL && *p == 0x7f ?
(char_u *)"\010" : (char_u *)"\177");
}
void
print_line(lnum, use_number)
linenr_t lnum;
int use_number;
{
char_u numbuf[20];
msg_outchar('\n');
if (curwin->w_p_nu || use_number)
{
sprintf((char *)numbuf, "%7ld ", (long)lnum);
set_highlight('n'); /* Highlight line numbers */
start_highlight();
msg_outstr(numbuf);
stop_highlight();
}
msg_prt_line(ml_get(lnum));
}
/*
* Implementation of ":file [fname]".
*/
void
do_file(arg, forceit)
char_u *arg;
int forceit;
{
char_u *fname, *sfname;
BUF *buf;
if (*arg != NUL)
{
/*
* The name of the current buffer will be changed.
* A new buffer entry needs to be made to hold the old
* file name, which will become the alternate file name.
*/
fname = curbuf->b_filename;
sfname = curbuf->b_sfilename;
curbuf->b_filename = NULL;
curbuf->b_sfilename = NULL;
if (setfname(arg, NULL, TRUE) == FAIL)
{
curbuf->b_filename = fname;
curbuf->b_sfilename = sfname;
return;
}
curbuf->b_notedited = TRUE;
buf = buflist_new(fname, sfname, curwin->w_cursor.lnum, FALSE);
if (buf != NULL)
curwin->w_alt_fnum = buf->b_fnum;
vim_free(fname);
vim_free(sfname);
}
/* print full filename if :cd used */
fileinfo(did_cd, FALSE, forceit);
}